#pragma once

#include "spin_box.hpp"
#include "spin_box_pack.hpp"
#include "between_face_include_config.hpp"

namespace beef {

    ConstantStrArray INTEGER_SIGN_SPIN_LIST = {"+", "-"};   // 整数符号选项
    ConstantStrArray CHECK_BOX_SPIN_LIST = {"OFF", "ON"};   // 复选框选项
    ConstantStrArray ERROR_MSG_SPIN_LIST = {"ERR", "VAL"};  // 错误消息占位
    ConstantStrArray EMPTY_OPTION_SPIN_LIST = {"NO", "VALUE"};


    struct MenuEditPlacing {
        PointType x = 0;
        PointType y = 0;         // 最左侧Box 在屏幕上的位置，基准点是box 字符的坐标基准，U8G2 的设定是字符左下角
        PointType w = 0;         // 显示数字时单个Box 的宽度，也是小数点的宽度
        PointType option_w = 0;  // 显示选项时单个Box 的宽度
        PointType h = 0;         // 高度
        PointType spacing = 0;   // 单个Box 之间的间隔
    };

    // TODO: 或许可以用一半宽度显示小数点

    /**
     * @brief MenuEdit 类用于编辑菜单项的值，支持多种数据类型和输入方式。
     *
     */
    class MenuEdit {
        static constexpr uint8_t MAX_DIGIT = MENU_EDIT_MAX_DIGIT;
        static constexpr uint8_t MAX_PRECISION = MENU_EDIT_MAX_PRECISION;

        static constexpr uint8_t BOX_GROUP_1_LEN = MAX_DIGIT;  // 加一位用来显示正负号
        static constexpr uint8_t BOX_GROUP_2_LEN = MAX_PRECISION;
        static constexpr uint8_t BOX_GROUP_LEN = max(BOX_GROUP_1_LEN, BOX_GROUP_2_LEN);

       private:
        MenuItem* _target_item = nullptr;  // 当前编辑的菜单项

        MenuItem _item;  // 编辑过程中使用的数据副本，编辑完成后更新到target_item

        SpinBoxPack<1> _sign_box;                   // 用来显示正负号
        SpinBoxPack<BOX_GROUP_LEN> _boxes;   // 用来显示数字、文本
        SpinBoxPack<BOX_GROUP_LEN> _boxes2;  // 仅用于显示浮点数的小数部分

        SpinBoxPack<BOX_GROUP_LEN>* _focused_box_group = nullptr;  // 当前获得焦点的SpinBoxPack

        bool _draw_sign = false;
        bool _draw_group_1 = false;
        bool _draw_group_2 = false;
        bool _lock_edit = false;  // 如果是no_value 类型菜单项，锁定编辑


        // 如果是comment、option 或check 类型，只用到_sign_box；
        // 如果是有符号整数，则_boxes 用来显示数字，_sign_box 显示正负号；
        // 如果浮点数，则用_boxes 显示整数部分，_boxes2 显示小数，_sign_box 显示正负号；

       public:
        MenuEdit() = default;


        void init(MenuItem* target, const MenuEditPlacing& placing,
                  const FramePlacing& fp, const char* title = nullptr) {
            if (target == nullptr) {
                return;
            }

            // 绘制边框
            // 要在draw 里绘制，就要把边框的配置数据保存在成员变量里，浪费内存，所以就放在init 里绘制
            if (fp.frame_w > 0 && fp.frame_h > 0) {
                if (title == nullptr) {
                    title = target->label;
                }
                oled_draw_frame_with_title(fp, title, MENU_FONT);
            }

            init(target, placing);
        }


        /**
         * @brief 初始化编辑器，绘制固定的编辑界面边框和标题
         *
         * @param target
         * @param placing
         */
        void init(MenuItem* target, const MenuEditPlacing& placing) {
            if (target == nullptr) {
                return;
            }

            _item = *target;
            _target_item = target;
            _draw_sign = true;
            _draw_group_1 = false;
            _draw_group_2 = false;
            _lock_edit = false;

            if (target->is_option() || target->is_comment()) {
                // 只需要一个spin box 显示option
                if (target->option_count() == 0) {
                    _sign_box.set_list(EMPTY_OPTION_SPIN_LIST, 2);
                }
                else {
                    _sign_box.set_list(target->data.list, target->len, target->index);
                }

                _sign_box.set_placing(placing.x, placing.y, placing.option_w, placing.h);  // 设置SpinBox的位置和大小
                _sign_box.set_focused(true);
            }
            else if (target->is_check()) {
                // 只需要一个spin box 显示check
                _sign_box.set_list(CHECK_BOX_SPIN_LIST, 2, target->checked() ? 1 : 0);
                _sign_box.set_placing(placing.x, placing.y, placing.option_w, placing.h);  // 设置SpinBox的位置和大小
                _sign_box.set_focused(true);
            }
            else if (!target->is_no_value()) {
                // 数字按照MenuItem 设置的位数显示
                auto l = target->number_len();
                if (l > MAX_DIGIT) {
                    l = MAX_DIGIT;  // 最多MAX_DIGIT 个数字
                }
                else if (l < 1) {
                    l = 1;  // 至少1个数字
                }

                _draw_group_1 = true;
                _focused_box_group = &_boxes;
                _boxes.set_focused_index(0);
                _boxes.set_focused(true);
                auto box_x = placing.x;
                _boxes.set_range(l, 0, 10);  // 设置SpinBox的范围
                _boxes.set_hex(false);

                if (target->type == menu_type::signed_value || target->type == menu_type::float_value) {
                    // 符号位单独处理
                    auto v = target->data.s;
                    _sign_box.set_list(INTEGER_SIGN_SPIN_LIST, 2, v < 0 ? 1 : 0);  // 设置符号位
                    _sign_box.set_placing(placing.x, placing.y, placing.w, placing.h);
                    box_x += placing.w + placing.spacing;
                }
                else {
                    if (target->type == menu_type::hex_value) {
                        _boxes.set_range(l, 0, 16);  // 十六进制范围是0-15
                    }
                    _draw_sign = false;
                }

                _boxes.set_placing(box_x, placing.y, placing.w, placing.h, placing.spacing);
                box_x += l * (placing.w + placing.spacing);

                if (target->type == menu_type::unsigned_value) {
                    auto v = target->data.u;
                    _boxes.split_sum(v, 10);
                }
                else if (target->type == menu_type::signed_value) {
                    auto v = target->data.s;
                    _boxes.split_sum(abs(v), 10);
                }
                else if (target->type == menu_type::hex_value) {
                    auto v = target->data.u;
                    _boxes.split_sum(v, 16);
                    _boxes.set_hex(true);  // 设置SpinBox按16进制显示
                }
                else if (target->is_float_point()) {
                    float v = target->float_value();
                    v = abs(v);

                    auto precision = target->float_precision();
                    if (precision > MAX_PRECISION) {
                        precision = MAX_PRECISION;
                    }
                    else if (precision == 0) {
                        precision = 1;
                    }

                    uint32_t frac_multiplier = 10;
                    for (uint8_t i = 0; i < precision; ++i) {
                        frac_multiplier *= 10;
                    }

                    uint32_t int_part = static_cast<uint32_t>(v);  // 整数部分
                    float frac_part = v - int_part;                // 小数部分
                    frac_part *= static_cast<float>(frac_multiplier);
                    uint32_t frac_int = static_cast<uint32_t>(frac_part);
                    frac_int += 5;  // 四舍五入
                    frac_int /= 10;

                    _draw_group_2 = true;
                    _boxes2.set_range(precision, 0, 10);
                    _boxes.split_sum(int_part, 10);
                    _boxes2.split_sum(frac_int, 10);
                    box_x += placing.w + placing.spacing;  // 留给小数点的位置
                    _boxes2.set_placing(box_x, placing.y, placing.w, placing.h, placing.spacing);
                }
            }
            else {
                // no value 类型的菜单项作用类似按钮，
                // 代表要立即执行的操作，所以不显示spin box
                _lock_edit = true;
                _draw_sign = false;
            }
        }


        bool draw(bool is_initial) {
            bool updated = false;

            if (_draw_sign) {
                updated = _sign_box.draw(is_initial);
            }
            if (_draw_group_1) {
                updated = _boxes.draw(is_initial);
                auto part_2_x = _boxes.right_x() + _boxes.spacing();

                u8g2.setFont(MENU_FONT);
                if (_item.is_integer()) {
                    // 显示要乘的幂，只有在初次绘制时才要执行这一步，因为后续编辑过程不会变更这部分显示内容
                    if (is_initial) {
                        auto i = _item.index;
                        if (i > 0) {
                            // 显示要乘的幂
                            u8g2.setCursor(part_2_x, _boxes.y());
                            u8g2.print('\'');
                            for (; i > 0; --i) {
                                u8g2.print('0');
                            }
                        }
                    }
                }
                else if (_draw_group_2) {
                    // 显示小数点
                    if (is_initial) {
                        u8g2.setCursor(part_2_x, _boxes.y());
                        u8g2.print('.');
                    }
                    updated = _boxes2.draw(is_initial);
                }
            }
            return updated;
        }


        bool changed() const {
            return _boxes.changed() || _boxes2.changed() || _sign_box.changed();
        }


        bool locked() const {
            return _lock_edit;
        }


        void set_lock_edit(bool lock) {
            _lock_edit = lock;
        }


        void move_left() {
            if (_focused_box_group != nullptr) {
                bool b = _focused_box_group->focus_left();
                if (b) {
                    // 移动到下一个box group，或sign_box
                    if (_focused_box_group == &_boxes2) {
                        // 显示了boxes2 则boxes 肯定会显示
                        _focused_box_group = &_boxes;
                        _boxes2.set_focused(false);
                        _boxes.set_focused_index(0);
                    }
                    else if (_focused_box_group == &_boxes) {
                        if (_draw_sign) {
                            _focused_box_group = nullptr;
                            _boxes.set_focused(false);
                            _sign_box.set_focused(true);
                        }
                        else if (_draw_group_2) {
                            _focused_box_group = &_boxes2;
                            _boxes.set_focused(false);
                            _boxes2.set_focused_index(0);
                        }
                    }
                }
            }
            else {
                // 当前是sign_box，移动到boxes2 或 boxes
                if (_draw_group_2) {
                    _focused_box_group = &_boxes2;
                    _sign_box.set_focused(false);
                    _boxes2.set_focused_index(0);
                }
                else if (_draw_group_1) {
                    _focused_box_group = &_boxes;
                    _sign_box.set_focused(false);
                    _boxes.set_focused_index(0);
                }
            }
        }


        void move_right() {
            if (_focused_box_group != nullptr) {
                bool b = _focused_box_group->focus_right();
                if (b) {
                    // 移动到下一个box group，或sign_box
                    if (_focused_box_group == &_boxes) {
                        if (_draw_group_2) {
                            _focused_box_group = &_boxes2;
                            _boxes.set_focused(false);
                            _boxes2.set_focused_index(_boxes2.box_count() - 1);
                        }
                        else if (_draw_sign) {
                            _focused_box_group = nullptr;
                            _boxes.set_focused(false);
                            _sign_box.set_focused(true);
                        }
                    }
                    else if (_focused_box_group == &_boxes2) {
                        if (_draw_sign) {
                            _focused_box_group = nullptr;
                            _boxes2.set_focused(false);
                            _sign_box.set_focused(true);
                        }
                        else {
                            _focused_box_group = &_boxes;
                            _boxes2.set_focused(false);
                            _boxes.set_focused_index(0);
                        }
                    }
                }
            }
            else {
                // 当前是sign_box，向右只可能先移动到boxes
                if (_draw_group_1) {
                    _focused_box_group = &_boxes;
                    _sign_box.set_focused(false);
                    _boxes.set_focused_index(_boxes.box_count() - 1);
                }
            }
        }


        void inc() {
            if (!_lock_edit) {
                if (_focused_box_group != nullptr)
                    _focused_box_group->inc();
                else
                    _sign_box.inc();
            }
        }


        void dec() {
            if (!_lock_edit) {
                if (_focused_box_group != nullptr)
                    _focused_box_group->dec();
                else
                    _sign_box.dec();
            }
        }


        const MenuItem& item() const {
            return _item;
        }


        /**
         * @brief 将编辑结果更新到暂存的 menu_item 中
         *
         */
        void update() {
            if (_target_item == nullptr) {
                return;
            }

            if (_item.is_option() || _item.is_comment()) {
                _item.set_option_index(_sign_box.current());
            }
            else if (_item.is_check()) {
                _item.set_checked(_sign_box.current() == 1);
            }
            else if (!_item.is_no_value()) {
                if (_item.type == menu_type::unsigned_value || _item.type == menu_type::hex_value) {
                    uint32_t v = _boxes.sum(0);
                    _item.data.u = v;
                }
                else if (_item.type == menu_type::signed_value) {
                    uint32_t v = _boxes.sum();
                    if (_sign_box.current() == 1) {
                        // 负数
                        _item.data.s = -static_cast<int32_t>(v);
                    }
                    else {
                        _item.data.s = static_cast<int32_t>(v);
                    }
                }
                else if (_item.is_float_point()) {
                    uint32_t int_part = _boxes.sum();
                    uint32_t frac_part = _boxes2.sum();

                    float f = static_cast<float>(int_part);

                    auto precision = _item.float_precision();
                    if (precision > MAX_PRECISION) {
                        precision = MAX_PRECISION;
                    }
                    else if (precision == 0) {
                        precision = 1;
                    }

                    float frac_multiplier = 1.0f;
                    for (uint8_t i = 0; i < precision; ++i) {
                        frac_multiplier *= 10.0f;
                    }

                    float frac_f = static_cast<float>(frac_part) / frac_multiplier;
                    f += frac_f;

                    if (_draw_sign && _sign_box.current() == 1) {
                        f = -f;
                    }

                    _item.data.f = f;
                }
            }
        }


        void finalize() {
            if (_target_item != nullptr) {
                *_target_item = _item;
            }
        }
    };
}  // namespace beef